package com.cqrt.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.cqrt.constant.RTErrorCodeEnum;
import com.cqrt.dto.RTTemplateLinkDocDTO;
import com.cqrt.entity.RTKnowTempDocDO;
import com.cqrt.entity.RTPlanJobLinkDO;
import com.cqrt.mapper.RTProjectKnowledgeLinkMapper;
import com.cqrt.mapper.RTProjectMapper;
import com.cqrt.service.RTProjectKnowledgeLinkService;
import com.hustcad.plm.basic.util.TyplmEntityBaseUtil;
import com.hustcad.plm.pdm.common.util.CommonUtil;
import com.hustcad.plm.pdm.file.service.TyplmFileHandleService;
import com.hustcad.plm.pdm.filevault.model.vo.FileDataVO;
import com.hustcad.plm.rpm.model.dto.remote.BatchInsertDocVO;
import com.hustcad.plm.rpm.model.dto.remote.DocDetailsVO;
import com.hustcad.plm.rpm.service.remote.TyppmRemotePdmService;
import com.ty.basic.constant.TableTypeConstrant;
import com.ty.basic.entity.IdentifierEntity;
import com.ty.basic.service.snow.SnowflakeIdComponent;
import com.ty.basic.session.TyAccountContext;
import com.ty.ppm.model.entity.job.Job;
import com.ty.security.util.TyCommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class RTProjectKnowledgeLinkServiceImpl implements RTProjectKnowledgeLinkService {

    @Resource
    private RTProjectKnowledgeLinkMapper rtProjectKnowledgeLinkMapper;
    @Resource
    private SnowflakeIdComponent snowflakeIdComponent;
    @Resource
    private TyplmFileHandleService fileHandleService;
    @Resource
    private RestTemplate restTemplate;

    @Resource
    private TyppmRemotePdmService typpmRemotePdmService;



    @Value("${main.service.url}")
    private String mainServiceUrl;

    @Resource
    private RTProjectMapper rtProjectMapper;

    @Override
    public void addTempLinkDoc(BatchInsertDocVO batchInsetDocVO) {
        List<DocDetailsVO> docList = batchInsetDocVO.getDocList();
        for (DocDetailsVO docDetailsVO : docList){
            String objectNumber = docDetailsVO.getObjectNumber();
            String name = docDetailsVO.getName();
            String projectOid=batchInsetDocVO.getParentNodeOid();
            List<BigInteger> Oid=rtProjectKnowledgeLinkMapper.selectNumberName(projectOid,objectNumber, name);
            if (Oid.size()>0){
               throw  RTErrorCodeEnum.KNOW_IS_REPEAT.message("名称重复");
            }
        }
        this.typpmRemotePdmService.insertRemoteDoc(batchInsetDocVO);
    }

    @Override
    public void uploadDoc(RTTemplateLinkDocDTO rtTemplateLinkDocDTO) {
        //1.查看当前计划是否在job-plan-link表
//        boolean tag=rtProjectKnowledgeLinkMapper.isExistLink(activityID);
//        List<BigInteger> docOidList=null;
//        if(tag) {
//            BigInteger planId = rtProjectKnowledgeLinkMapper.selectPlanById(activityID);
//            if (ObjectUtil.isEmpty(planId))
//                throw RTErrorCodeEnum.DOC_NOT_EXIST.getException("当前项目任务未关联文档，无法下载");
//             docOidList = rtProjectKnowledgeLinkMapper.selectJobById(planId);
//        }else {
//            docOidList=rtProjectKnowledgeLinkMapper.selectJobById(Tools.toBigInteger(activityID));
//        }

        Job job= rtProjectKnowledgeLinkMapper.selectById(rtTemplateLinkDocDTO.getActivityID());
        List<RTTemplateLinkDocDTO> templateLinkDocDTOS = queryTemplateDetailByOid(job.getActivityID());
        if (CollUtil.isEmpty(templateLinkDocDTOS)) {
            throw RTErrorCodeEnum.DOC_NOT_EXIST.getException("当前项目任务未关联文档，无法下载");
        }

        List<BigInteger> docOidList = templateLinkDocDTOS
                .stream()
                .map(RTTemplateLinkDocDTO::getLatestVersionID)
                .collect(Collectors.toList());

        //去重
        List<BigInteger> docList = CollectionUtils.isEmpty(docOidList)
                ? new ArrayList<>()
                : docOidList.stream().distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(docList)) {
            List<BigInteger> fileOidList = new ArrayList<>();
            for (BigInteger fileOId : docList) {
                IdentifierEntity entity = new IdentifierEntity();
                entity.setOid(fileOId);
                entity.setOtype(TableTypeConstrant.TY_DOC_OTYPE);
                TyCommonUtils.requireNonNull(entity, "entity");
                CommonUtil.checkIdentifierNotNull(entity);
                List<FileDataVO> fileListByEntity = this.fileHandleService.getFileListByEntity(entity);
                for (FileDataVO fileDataVO : fileListByEntity) {
                    fileOidList.add(BigInteger.valueOf(Long.parseLong(fileDataVO.getFileID())));
                }
            }
            HttpHeaders headers = new HttpHeaders();
            headers.set(HttpHeaders.AUTHORIZATION, TyAccountContext.getToken());
            headers.set(HttpHeaders.CONTENT_TYPE, "application/json");
            HttpEntity<List<BigInteger>> requestEntity = new HttpEntity<>(fileOidList, headers);
            try {
                ResponseEntity<byte[]> responseEntity = restTemplate.exchange(
                        mainServiceUrl,
                        HttpMethod.POST,
                        requestEntity,
                        byte[].class);
                if (responseEntity.getBody()==null) {
                    throw RTErrorCodeEnum.DOC_NOT_EXIST.getException("当前文档为空，无法下载");
                }
                HttpServletResponse response = ((ServletRequestAttributes) Objects.requireNonNull(
                        RequestContextHolder.getRequestAttributes()))
                        .getResponse();
                if (responseEntity.getStatusCode().is2xxSuccessful()) {
                    MediaType contentType = responseEntity.getHeaders().getContentType();
                    String contentDisposition = responseEntity.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION);
                    String filename = extractFilename(contentDisposition, "download.zip");
                    if (isZipFile(contentType, filename)) {
                        // 处理ZIP压缩包
                        assert response != null;
                        handleZipDownload(response, Objects.requireNonNull(responseEntity.getBody()), filename);
                    } else if (isMultiPart(contentType)) {
                        assert response != null;
                        handleMultiPartDownload(response, responseEntity);
                    } else {
                        // 处理单文件下载
                        handleSingleFileDownload(response, responseEntity.getBody(), contentType, filename);
                    }
                } else {
                    // 处理错误响应
                    assert response != null;
                    response.setStatus(responseEntity.getStatusCodeValue());
                    response.getWriter().write("主服务返回错误: " + responseEntity.getStatusCode());
                }
            } catch (IOException e) {
                throw RTErrorCodeEnum.DOC_TYPE_ERROR.getException("文件类型错误，无法下载");
            }
        }
    }

    private String extractFilename(String contentDisposition, String defaultFilename) {
        if (StringUtils.isBlank(contentDisposition)) {
            return defaultFilename;
        }
        String filename = null;
        // 格式1：attachment; filename="example.pdf"
        if (contentDisposition.contains("filename=")) {
            String[] parts = contentDisposition.split("filename=");
            if (parts.length > 1) {
                filename = parts[1].replace("\"", "").trim();
            }
        }
        // 格式2：attachment; filename*=utf-8''%E6%96%87%E4%BB%B6%E5%90%8D.pdf
        else if (contentDisposition.contains("filename*=")) {
            String[] parts = contentDisposition.split("filename\\*=");
            if (parts.length > 1) {
                String value = parts[1].trim();
                // 处理RFC 5987编码的文件名
                if (value.startsWith("utf-8''") || value.startsWith("UTF-8''")) {
                    filename = decodeRfc5987(value.substring(7));
                }
            }
        }
        // 如果未提取到有效文件名，使用默认值
        if (StringUtils.isBlank(filename)) {
            return defaultFilename;
        }
        return sanitizeFilename(filename);
    }

    private String decodeRfc5987(String encoded) {
        try {
            return URLDecoder.decode(encoded, StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException e) {
            log.warn("文件名解码失败", e);
            return encoded;
        }
    }

    private String sanitizeFilename(String filename) {
        String cleanName = new File(filename).getName();
        return cleanName.replaceAll("[\\\\/:*?\"<>|]", "_");
    }

    private void handleZipDownload(HttpServletResponse response, byte[] content, String filename)
            throws IOException {
        response.setContentType("application/zip");
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
                           "attachment; filename=\"" + filename + "\"");
        response.setContentLength(content.length);
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            outputStream.write(content);
            outputStream.flush();
        }
    }

    /**
     * 处理multipart/form-data格式的多文件下载
     */
    private void handleMultiPartDownload(HttpServletResponse response, ResponseEntity<byte[]> responseEntity)
            throws IOException {
        // 获取原始Content-Type
        String contentType = Objects.requireNonNull(responseEntity.getHeaders().getContentType()).toString();
        response.setContentType(contentType);
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
                           "attachment; filename=\"multiple_files.bin\"");
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            outputStream.write(Objects.requireNonNull(responseEntity.getBody()));
            outputStream.flush();
        }
    }

    /**
     * 处理单文件下载
     */
    private void handleSingleFileDownload(HttpServletResponse response, byte[] content,
                                          MediaType contentType, String filename)
            throws IOException {
        if (contentType != null) {
            response.setContentType(contentType.toString());
        } else {
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        }
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
                           "attachment; filename=\"" + filename + "\"");
        response.setContentLength(content.length);
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            outputStream.write(content);
            outputStream.flush();
        }
    }

    /**
     * 判断是否为ZIP文件
     */
    private boolean isZipFile(MediaType contentType, String filename) {
        if (contentType != null && contentType.toString().contains("application/zip")) {
            return true;
        }
        return filename != null && filename.toLowerCase().endsWith(".zip");
    }

    /**
     * 判断是否为multipart/form-data格式
     */
    private boolean isMultiPart(MediaType contentType) {
        return contentType != null && contentType.toString().startsWith("multipart/form-data");
    }

    @Override
    public List<RTTemplateLinkDocDTO> queryTemplateDetailByOid(BigInteger id) {
        List<BigInteger> pjIdList=rtProjectKnowledgeLinkMapper.selectPjIdById(id);
        RTPlanJobLinkDO rtPlanJobLinkDO=null;
        if (CollUtil.isNotEmpty(pjIdList)){

            rtPlanJobLinkDO= rtProjectKnowledgeLinkMapper.selectIsJobById(pjIdList.get(0));
        }
        //1.获取模板计划的文档

        List<RTTemplateLinkDocDTO> rtTemplateLinkDocDOList=new ArrayList<>();
        if (ObjectUtil.isNotNull(rtPlanJobLinkDO)) {
            List<RTTemplateLinkDocDTO> templateLinkDocDOS= rtProjectKnowledgeLinkMapper.selectDocById(id);
            List<RTTemplateLinkDocDTO> rtTemplateLinkDocDOS= rtProjectKnowledgeLinkMapper.selectDocById(rtPlanJobLinkDO.getPlanoid());
            if (CollUtil.isNotEmpty(templateLinkDocDOS)){
                rtTemplateLinkDocDOList.addAll(templateLinkDocDOS);
            }
            if (CollUtil.isNotEmpty(rtTemplateLinkDocDOS)){
                rtTemplateLinkDocDOList.addAll(rtTemplateLinkDocDOS);
            }

        }else {
            //1.获取模板计划的文档
            List<RTTemplateLinkDocDTO> templateLinkDocDOS= rtProjectKnowledgeLinkMapper.selectDocById(id);
            if (CollUtil.isNotEmpty(templateLinkDocDOS)){
                rtTemplateLinkDocDOList.addAll(templateLinkDocDOS);
            }
        }
        for (RTTemplateLinkDocDTO rtTemplateLinkDocDTO : rtTemplateLinkDocDOList){
            rtTemplateLinkDocDTO.setOidStr(rtTemplateLinkDocDTO.getOid().toString());
            rtTemplateLinkDocDTO.setProjectIdStr(rtTemplateLinkDocDTO.getProjectId().toString());
            rtTemplateLinkDocDTO.setLatestVersionIDStr(rtTemplateLinkDocDTO.getLatestVersionID().toString());
        }
        List<RTKnowTempDocDO> rtKnowTempDocDOS=rtProjectKnowledgeLinkMapper.selectKnowTempDocByJobId(id);
        for (RTKnowTempDocDO rtKnowTempDocDO : rtKnowTempDocDOS){
            RTTemplateLinkDocDTO rtTemplateLinkDocDTO=new RTTemplateLinkDocDTO();
            BeanUtils.copyProperties(rtKnowTempDocDO,rtTemplateLinkDocDTO);
            rtTemplateLinkDocDTO.setOidStr(rtKnowTempDocDO.getOid().toString());
            rtTemplateLinkDocDTO.setProjectIdStr(rtKnowTempDocDO.getProjectId().toString());
            rtTemplateLinkDocDTO.setLatestVersionIDStr(rtKnowTempDocDO.getLatestVersionID().toString());

            rtTemplateLinkDocDOList.add(rtTemplateLinkDocDTO);
        }



        return rtTemplateLinkDocDOList;
    }



    @Override
    public void updateDocDetail(List<RTTemplateLinkDocDTO> rtTemplateLinkDocDTOList) {
        BigInteger oid = rtTemplateLinkDocDTOList.get(0).getOid();
        for (RTTemplateLinkDocDTO rtTemplateLinkDocDTO : rtTemplateLinkDocDTOList) {
            BigInteger projectId = rtTemplateLinkDocDTO.getProjectId();
            List<BigInteger> groupOid = rtProjectMapper.selectGroupByName("PROJECT DIRECTOR", projectId);
            if (!CollUtil.isEmpty(groupOid)) {
                List<BigInteger> userIds = rtProjectMapper.selectUserIdByGroupId(groupOid.get(0));
                if (CollUtil.isEmpty(userIds)) {
                    boolean isDirector = false;
                    for (BigInteger userId : userIds) {
                        BigInteger user = TyAccountContext.getUser().getOid();
                        if (userId.equals(user)) {
                            isDirector = true;
                        }
                    }
                    if (!isDirector) {
                        throw RTErrorCodeEnum.KNOW_IS_TEMPLATE.getException("模板不允许修改");
                    }
                }
            }
            if ("Y".equals(rtTemplateLinkDocDTO.getIsTemplate())){

            throw RTErrorCodeEnum.KNOW_IS_TEMPLATE.getException("模板不允许修改");
            }
            String objectNumber = rtTemplateLinkDocDTO.getObjectNumber();
            List<BigInteger> latestVersionID=rtProjectKnowledgeLinkMapper.selectlastVersionId(oid,objectNumber);


            if (!CollUtil.isEmpty(latestVersionID)) {
                for (BigInteger bigInteger : latestVersionID) {
                    String exoid=bigInteger.toString();
                    rtProjectKnowledgeLinkMapper.deleteRomate(exoid);
                }
            }else {
                throw RTErrorCodeEnum.KNOW_IS_TEMPLATE.getException("模板不允许修改");
            }
            rtProjectKnowledgeLinkMapper.deleteDocByOId(oid,objectNumber);
        }
        //addTempLinkDoc(rtTemplateLinkDocDTOList);
    }

    @Override
    public void addTempKnowDoc(List<RTKnowTempDocDO> rtKnowTempDocDOs) {
        for (RTKnowTempDocDO rtKnowTempDocDO : rtKnowTempDocDOs) {
            List<RTKnowTempDocDO> rtKnowTempDocDOS = rtProjectKnowledgeLinkMapper.selectKnowTempDocByPlanActivityId(
                    rtKnowTempDocDO.getPlanActiveOid());
            for (RTKnowTempDocDO rtKnowTempDocDO1 : rtKnowTempDocDOS) {
                if(StringUtils.isNotEmpty(rtKnowTempDocDO1.getIdentifierDisplayName())) {
                    if (rtKnowTempDocDO1.getIdentifierDisplayName().equals(
                            rtKnowTempDocDO.getIdentifierDisplayName())) {
                        throw RTErrorCodeEnum.KNOW_IS_REPEAT.getException("知识推送文档重复");
                    }
                }
            }
            BigInteger bigInteger = snowflakeIdComponent.getInstance().nextId();
            rtKnowTempDocDO.setOType("rt.inteplm.template.doc.link");
            rtKnowTempDocDO.setOid(bigInteger);
            rtProjectKnowledgeLinkMapper.insertKnowTempDoc(rtKnowTempDocDO);
        }
    }

    @Override
    public List<RTKnowTempDocDO> queryTempKnowDoc(BigInteger planActivityId) {
        List<RTKnowTempDocDO> rtKnowTempDocDOS=rtProjectKnowledgeLinkMapper.selectKnowTempDocByPlanActivityId(planActivityId);
        return rtKnowTempDocDOS;
    }

    @Override
    public void deleteTempDoc(String name ,String jobname) {
        rtProjectKnowledgeLinkMapper.deleteKnowTempDoc(name,jobname);
    }
    @Override
    public List<String> selectIsTemp(String name ,String jobname) {
        List<String> isTemp=rtProjectKnowledgeLinkMapper.selectIsTemp(name,jobname);
        return isTemp;
    }

}
